package spark.mgworkplace.job.udf

import java.math.RoundingMode
import java.sql.Timestamp
import java.text.SimpleDateFormat
import spark.mgworkplace.job.udf.TransformKit._
import spark.mgworkplace.job.param.ParamKit._
import spark.mgworkplace.job.param

/**
  *
  * @author eureka.wh
  * @since 2019/6/14
  */
object UdfKit {

  // 限制年月日(Ymd)时间范围
  def limitYmdTime(time: Timestamp, borderBeginYmdStr: String, borderEndYmdStr: String) = {
    val sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
    val timeStr = sdf.format(time)
    timeStr >= borderBeginYmdStr && timeStr <= borderEndYmdStr
  }

  // 限制时分秒(Hms)时间范围
  def limitHmsTime(time: Timestamp, borderBeginHmsStr: String, borderEndHmsStr: String) = {
    val sdf = new SimpleDateFormat("HH:mm:ss")
    val timeStr = sdf.format(time)
    timeStr >= borderBeginHmsStr && timeStr <= borderEndHmsStr
  }

  // 夜间行车时间为 (当日)21:00 ~ (次日)07:00
  // TODO: 该方法考虑跨天边界,只考虑跨一天的情况，超过跨一天为异常行车信息，不予统计
  def handleNightDrivingTime(startTime: Timestamp,stopTime: Timestamp) = {
    var resultDob = 0.0
    // 实际开始结束时间，字符串
    val startTimeStr = timeStamp2String(startTime, "yyyy-MM-dd HH:mm:ss")
    val stopTimeStr = timeStamp2String(stopTime, "yyyy-MM-dd HH:mm:ss")
    // 边界时间，字符串
    val borderBeginStr = timeStamp2String(startTime, s"yyyy-MM-dd '${nightDrivingBeginTimeStr}'")
    var borderEndStr = timeStamp2String(stopTime, s"yyyy-MM-dd '${nightDrivingSeparationTimeStr}'")

    // startTime、stopTime为同一天，startTimeStr、任意一个大于跨天的临界值，则右边界临界值需要改变为跨天的情况
    if ((startTimeStr.substring(0,10) == stopTimeStr.substring(0,10))) {
      if ((startTimeStr > borderEndStr) || (stopTimeStr > borderEndStr)) {
        // 边界结束时间添加1天，并修改为'2019-06-15 07:00:00'，方法的形参是不可变的，下面不能直接用stopTime作为参数
        // 日期加一天
        val x = string2Timestamp(stopTimeStr)
        borderEndStr = timeStampChangeRetStr(x, 1)
        // 日期加一天后添加下边界
        borderEndStr = timeStamp2String(string2Timestamp(borderEndStr), s"yyyy-MM-dd '${nightDrivingEndTimeStr}'")
      }
    }

    // 计算使用时间，字符串，默认为实际开始结束时间
    var actStartTimeStr = startTimeStr
    var actStopTimeStr = stopTimeStr
    val startMeetBln = (startTimeStr >= borderBeginStr) && (startTimeStr <= borderEndStr)
    val endMeetBln = (stopTimeStr >= borderBeginStr) && (stopTimeStr <= borderEndStr)

    // 实际开始时间 < 左边界时间，实际结束时间位于边界区间内，取左边界时间为计算开始时间
    if ((startTimeStr < borderBeginStr) && endMeetBln) {
      actStartTimeStr = borderBeginStr
    }
    // 实际结束时间 > 右边界时间，实际开始时间位于边界区间内，取右边界时间为计算结束时间
    else if ((stopTimeStr > borderEndStr) && startMeetBln) {
      actStopTimeStr = borderEndStr
    }
    //  实际开始时间 < 左边界时间 且  实际结束时间 > 右边界时间
    else if ((startTimeStr < borderBeginStr) && (stopTimeStr > borderEndStr)) {
      actStartTimeStr = borderBeginStr
      actStopTimeStr = borderEndStr
    }
    // 在正常的夜间行车范围内的
    else if((startTimeStr >= borderBeginStr) && (stopTimeStr <= borderEndStr)) {
      actStartTimeStr = startTimeStr
      actStopTimeStr = stopTimeStr
    }
    else {
      actStartTimeStr = "0"
      actStopTimeStr = "0"
    }

    val actStartTimeTmsp = string2Timestamp(actStartTimeStr)
    val actStopTimeTmsp = string2Timestamp(actStopTimeStr)
    resultDob = (actStopTimeTmsp.getTime / 1000.0 - actStartTimeTmsp.getTime / 1000.0) / 3600.0
    doubleRetainDecimal(resultDob, 2, RoundingMode.HALF_UP)
  }

  /** *
    * 求时间差，并处理一天内的边界问题，以早高峰为例：
    * 1、开始时间小于07:00，结束时间位于7~10之间
    * 2、结束时间大于10:00，开始时间位于7~10之间
    * 3、开始时间小于07:00，结束时间大于10:00
    */
  // TODO: 该方法不考虑跨天边界问题
  def diffTimeByTimestamp(startTime: Timestamp, stopTime: Timestamp, borderBeginHmsStr: String, borderEndHmsStr: String) = {
    var resultDob = 0.0
    val hmsStartStr = timeStamp2String(startTime, "HH:mm:ss")
    val hmsStopStr = timeStamp2String(stopTime, "HH:mm:ss")
    var ymdhmsStartStr = timeStamp2String(startTime)
    var ymdhmsStopStr = timeStamp2String(stopTime)
    val startMeetBln = (hmsStartStr >= borderBeginHmsStr) && (hmsStartStr <= borderEndHmsStr)
    val endMeetBln = (hmsStopStr >= borderBeginHmsStr) && (hmsStopStr <= borderEndHmsStr)

    // 开始时间小于07:00，结束时间位于7~10之间(包含边界)
    if ((hmsStartStr < borderBeginHmsStr) && endMeetBln) {
      ymdhmsStartStr = new StringBuilder(ymdhmsStartStr).replace(11, 19, borderBeginHmsStr).toString()
    }
    // 结束时间大于10:00，开始时间位于7~10之间(包含边界)
    else if ((hmsStopStr > borderEndHmsStr) && startMeetBln) {
      ymdhmsStopStr = new StringBuilder(ymdhmsStopStr).replace(11, 19, borderEndHmsStr).toString()
    }
    // 开始时间小于07:00，结束时间大于10:00
    else if (!startMeetBln && !endMeetBln) {
      // 10 - 7 = 3
      val delta = borderEndHmsStr.substring(0, 2).toInt - borderBeginHmsStr.substring(0, 2).toInt
      resultDob = 60 * 60 * delta / 3600.0
    }

    val ymdhmsStartTmsp = string2Timestamp(ymdhmsStartStr)
    val ymdhmsStopTmsp = string2Timestamp(ymdhmsStopStr)
    // 13位数时间戳转10位数时间戳,求时间差，并转换成小时
    val ymdhmsStartLong = ymdhmsStartTmsp.getTime / 1000.0
    val ymdhmsStopLong = ymdhmsStopTmsp.getTime / 1000.0
    resultDob = (ymdhmsStopLong - ymdhmsStartLong) / 3600.0
    // 采用四舍五入的方法保留2位小数(如果小数最后一位为0，则会自动省略)
    doubleRetainDecimal(resultDob, 2, RoundingMode.HALF_UP)
  }

}
